package de.hs_mannheim.visualscheduler.gui;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import de.hs_mannheim.visualscheduler.scheduling.AbstractScheduler;
import de.hs_mannheim.visualscheduler.scheduling.FirstComeFirstServed;
import de.hs_mannheim.visualscheduler.scheduling.LongestJobFirst;
import de.hs_mannheim.visualscheduler.scheduling.PriorityBased;
import de.hs_mannheim.visualscheduler.scheduling.ProcessDefinition;
import de.hs_mannheim.visualscheduler.scheduling.RoundRobin;
import de.hs_mannheim.visualscheduler.scheduling.Scheduler;
import de.hs_mannheim.visualscheduler.scheduling.ShortestJobFirst;

/**
 * The Class SettingsGUI provides functionality for setting ProcessDefintions and selecting a scheduler.
 */
public class SettingsGUI extends JPanel implements ActionListener, ListSelectionListener, ItemListener {
	private static final long		serialVersionUID	= 4469729598193342667L;
	private final ProcessTableModel	processes			= new ProcessTableModel();
	private final JComboBox			schedulerComboBox;
	private final JSpinner			spinnerTimeslices	= new JSpinner(new SpinnerNumberModel(5, 1, 100, 1));
	private final JTextField		textArrival			= new JTextField();
	private final JTextField		textPriority		= new JTextField();
	private final JTextField		textRuntime			= new JTextField();
	private final JTextField		textName			= new JTextField();
	private final JButton			buttonAdd			= new JButton("Add Process");
	private final JButton			buttonRemove		= new JButton("Remove Process");
	private final JTable			tableProcesses;

	/**
	 * Instantiates a new settings gui.
	 */
	public SettingsGUI() {
		super(new BorderLayout());

		((BorderLayout)getLayout()).setHgap(10);
		((BorderLayout)getLayout()).setVgap(10);
		
		tableProcesses = new JTable(processes);
		schedulerComboBox = new JComboBox(new Scheduler[] {
				new RoundRobin(),
					new FirstComeFirstServed(),
					new PriorityBased(true),
					new PriorityBased(false),
					new ShortestJobFirst(true),
					new LongestJobFirst(true),
					new ShortestJobFirst(false),
					new LongestJobFirst(false)
					
				});
		schedulerComboBox.addItemListener(this);
		tableProcesses.setAutoCreateRowSorter(true);
		JPanel algorithmBar = new JPanel(new BorderLayout());
		algorithmBar.add(schedulerComboBox, BorderLayout.WEST);
		algorithmBar.add(new JLabel("Timeslice ", JLabel.RIGHT));
		algorithmBar.add(spinnerTimeslices, BorderLayout.EAST);
		add(algorithmBar, BorderLayout.NORTH);

		final JPanel buttonedTable = new JPanel(new BorderLayout());
		buttonedTable.add(new JScrollPane(tableProcesses), BorderLayout.CENTER);
		buttonedTable.add(buttonRemove, BorderLayout.SOUTH);
		buttonedTable.setBorder(BorderFactory.createTitledBorder("Processes"));
		add(buttonedTable, BorderLayout.CENTER);
		
		buttonRemove.setEnabled(false);
		
		final JPanel addProcessToolbar = new JPanel(new GridLayout(0, 2));
		((GridLayout)addProcessToolbar.getLayout()).setVgap(5);
		addProcessToolbar.add(new JLabel("Name"));
		addProcessToolbar.add(textName);
		addProcessToolbar.add(new JLabel("Priority"));
		addProcessToolbar.add(textPriority);
		addProcessToolbar.add(new JLabel("Runtime"));
		addProcessToolbar.add(textRuntime);
		addProcessToolbar.add(new JLabel("Arrival"));
		addProcessToolbar.add(textArrival);
		addProcessToolbar.add(new JPanel());
		addProcessToolbar.add(buttonAdd);
		addProcessToolbar.setBorder(BorderFactory.createTitledBorder("Add Process"));
		
		add(addProcessToolbar, BorderLayout.SOUTH);

		// Register Listeners
		buttonRemove.addActionListener(this);
		buttonAdd.addActionListener(this);
		tableProcesses.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		tableProcesses.getSelectionModel().addListSelectionListener(this);
	}

	@Override
	public void actionPerformed(final ActionEvent arg0) {
		if (buttonAdd == arg0.getSource()) {
			processes.add(new ProcessDefinition(Integer.parseInt(textRuntime.getText()), Integer
					.parseInt(textArrival.getText()), Integer.parseInt(textPriority.getText()), textName
					.getText()));
		} else if (buttonRemove == arg0.getSource()) {
			// Transform the row-number into a model index (taking sorting in account)
			int modelIndex = tableProcesses.getRowSorter().convertRowIndexToModel(tableProcesses.getSelectedRow());
			processes.remove(modelIndex);
		}
	}
	
	/**
	 * Gets the time slice length. Relevant only for RoundRobin
	 * 
	 * @return the time slice length
	 */
	public int getTimeSliceLength(){
		return ((Integer)spinnerTimeslices.getValue());
	}

	/**
	 * Gets the processes defined.
	 * 
	 * @return the processes
	 */
	public ProcessDefinition[] getProcesses() {
		return processes.getProcesses();
	}

	/**
	 * Gets the scheduler select.
	 * 
	 * @return the scheduler
	 */
	public Scheduler getScheduler() {
		return (Scheduler) schedulerComboBox.getSelectedItem();
	}

	/**
	 * Sets the processes to display.
	 * 
	 * @param processes
	 *            the new processes
	 */
	public void setProcesses(final ProcessDefinition[] processes) {
		this.processes.setProcesses(processes);
	}

	@Override
	public void valueChanged(ListSelectionEvent e) {
		// Enable Remove-Button only if a row is selected in the Process-Table
		if(e.getFirstIndex() >= 0) {
			buttonRemove.setEnabled(true);
		} else {
			buttonRemove.setEnabled(false);
		}
	}

	@Override
	public void itemStateChanged(ItemEvent e) {
		if("RoundRobin (RR)".equals(((AbstractScheduler)schedulerComboBox.getSelectedItem()).toString())){
			spinnerTimeslices.setEnabled(true);
		} else {
			spinnerTimeslices.setEnabled(false);
		}
	}
}
